package org.stone.project.tx.config;

import cn.hutool.core.util.ObjectUtil;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.stone.project.tx.pojo.dto.UuidUserDto;
import org.stone.project.tx.pojo.dto.UserCtxDto;
import org.stone.project.tx.pojo.dto.UuidUserCtxDto;
import org.stone.project.tx.prop.TxProp;
import org.stone.project.tx.utils.UserLockUtil;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
public class InMemoryCtxHolder implements CtxHolderInterface{
    @Autowired
    private TxProp txProp;

    @Autowired
    private RedissonClient redissonClient;

    private static Map<String,Map<String,UuidUserCtxDto> > userCtx = new HashMap<>();

    private static Map<ChannelHandlerContext, UuidUserDto> ctxUser = new HashMap();

    @Override
    public Map<String, UuidUserCtxDto> findByUserIdAll(String userId) {
        Map<String, UuidUserCtxDto> uuidUserCtxDtos = InMemoryCtxHolder.userCtx.get(userId);
        return uuidUserCtxDtos;
    }

    @Override
    public ChannelHandlerContext findByUserId(String userId,String linkId) {
        Map<String, UuidUserCtxDto> uuidUserCtxDtos = InMemoryCtxHolder.userCtx.get(userId);
        UuidUserCtxDto uuidUserCtxDto = uuidUserCtxDtos.get(linkId);
        return uuidUserCtxDto.getCtx();
    }

    @Override
    public UuidUserDto findByCtx(ChannelHandlerContext ctx) {
        UuidUserDto userId = InMemoryCtxHolder.ctxUser.get(ctx);
        return userId;
    }

    @Override
    public void addUserCtx(String userId,String linkId, ChannelHandlerContext ctx) {
        RLock rLock = null;
        try {
            rLock = UserLockUtil.lockUser(userId);
        } catch (InterruptedException e) {
            throw new IllegalArgumentException("用户上锁失败");
        }
        try {
            Integer connectionByUserNum = getConnectionByUserNum(userId);
            if (connectionByUserNum >= txProp.getUserMaxLinkNum()){
                throw new IllegalArgumentException("超过最大连接数");
            }
            UuidUserDto uuidUserDto = InMemoryCtxHolder.ctxUser.get(ctx);
            if (ObjectUtil.isNotNull(uuidUserDto)){
                throw new IllegalArgumentException("连接已存在");
            }
            Map<String, UuidUserCtxDto> uuidUserCtxDtoMap = InMemoryCtxHolder.userCtx.get(userId);
            UuidUserCtxDto uuidUserCtxDto = new UuidUserCtxDto();
            /**
             * 用户对象
             */
            if (ObjectUtil.isNotEmpty(uuidUserCtxDtoMap)){
                uuidUserCtxDto.setCtx(ctx);
                uuidUserCtxDto.setLinkTime(new Date());
                uuidUserCtxDtoMap.put(linkId,uuidUserCtxDto);
            }
            /**
             * 用户不存在
             */
            else {
                uuidUserCtxDtoMap = new HashMap<>();
                uuidUserCtxDto.setCtx(ctx);
                uuidUserCtxDto.setLinkTime(new Date());
                uuidUserCtxDtoMap.put(linkId,uuidUserCtxDto);
            }
            /**
             * 连接对象已存在
             */
            if (ObjectUtil.isNotNull(uuidUserDto)){

            }
            /**
             * 连接对象不存在
             */
            else {
                uuidUserDto = new UuidUserDto();
                uuidUserDto.setUserId(userId);
                uuidUserDto.setUuid(linkId);
            }


            InMemoryCtxHolder.userCtx.put(userId,uuidUserCtxDtoMap);
            InMemoryCtxHolder.ctxUser.put(ctx,uuidUserDto);
        }finally {
            rLock.unlock();
        }
    }

    @Override
    public void removeUserCtx(String userId,String linkId) {
        RLock rLock = null;
        try {
            rLock = UserLockUtil.lockUser(userId);
        } catch (InterruptedException e) {
            throw new IllegalArgumentException("删除用户失败");
        }
        try {
            Map<String, UuidUserCtxDto> uuidUserCtxDtoMap = InMemoryCtxHolder.userCtx.get(userId);
            if (ObjectUtil.isNotNull(uuidUserCtxDtoMap)){
                UuidUserCtxDto remove = uuidUserCtxDtoMap.remove(linkId);
                //如果删除对象不为空
                if (ObjectUtil.isNotNull(remove)){
                    InMemoryCtxHolder.ctxUser.remove(remove.getCtx());
                }
            }
        }finally {
            rLock.unlock();
        }
    }

    @Override
    public UserCtxDto linkRemoveExist(ChannelHandlerContext ctx) {
        UserCtxDto userCtxDto = new UserCtxDto();
        userCtxDto.setCtx(ctx);
        if (ObjectUtil.isNotNull(ctx)){
            UuidUserDto userId = InMemoryCtxHolder.ctxUser.get(ctx);
            if (ObjectUtil.isNotNull(userId)){
                RLock rLock = null;
                try {
                    rLock = UserLockUtil.lockUser(userId.getUserId());
                } catch (InterruptedException e) {
                    throw new IllegalArgumentException("删除用户失败");
                }
                try {
                    InMemoryCtxHolder.ctxUser.remove(ctx);
                }finally {
                    rLock.unlock();
                }
                userCtxDto.setUserId(userId.getUserId());
                userCtxDto.setUuid(userId.getUuid());
            }
        }
        return userCtxDto;
    }

    @Override
    public UserCtxDto unLinkRemoveExist(ChannelHandlerContext ctx) {
        UserCtxDto userCtxDto = new UserCtxDto();
        userCtxDto.setCtx(ctx);
        if (ObjectUtil.isNotNull(ctx)){
            UuidUserDto userId = InMemoryCtxHolder.ctxUser.get(ctx);
            if (ObjectUtil.isNotNull(userId)){
                RLock rLock = null;
                try {
                    rLock = UserLockUtil.lockUser(userId.getUserId());
                } catch (InterruptedException e) {
                    throw new IllegalArgumentException("删除用户失败");
                }
                try {
                    InMemoryCtxHolder.ctxUser.remove(ctx);
                }finally {
                    rLock.unlock();
                }

                userCtxDto.setUserId(userId.getUserId());
                userCtxDto.setUuid(userId.getUuid());
            }
        }
        return userCtxDto;
    }

    @Override
    public Integer getConnectionNum() {
        return ctxUser.size();
    }

    @Override
    public Integer getConnectionUserNum() {
        return userCtx.size();
    }

    @Override
    public Integer getConnectionByUserNum(String userId) {
        int size = 0;
        try {
            Map<String, UuidUserCtxDto> uuidUserCtxDtoMap = userCtx.get(userId);
            size = uuidUserCtxDtoMap.size();
        } catch (Exception e) {
            log.info("用户{}并发异常",userId);
        }
        return size;
    }

    public Map<ChannelHandlerContext, UuidUserDto> getAllCtx(){
        return ctxUser;
    }
}
